﻿using System.Windows;
using System.Windows.Media;

// ReSharper disable once CheckNamespace
namespace WpfExtensions.Xaml.ExtensionMethods;

internal static class DependencyObjectExtensions
{
    /// <summary>
    /// Finds a parent of a given item on the visual tree.
    /// </summary>
    /// <typeparam name="T">The type of the queried item.</typeparam>
    /// <param name="child">A direct or indirect child of the
    /// queried item.</param>
    /// <returns>The first parent item that matches the submitted
    /// type parameter. If not matching item can be found, a null
    /// reference is being returned.</returns>
    public static T TryFindParent<T>(this DependencyObject child) where T : DependencyObject
    {
        while (true)
        {
            //get parent item
            DependencyObject parentObject = child.GetParentObject();

            //we've reached the end of the tree
            if (parentObject == null) return null;

            //check if the parent matches the type we're looking for
            if (parentObject is T parent) return parent;
            child = parentObject;
        }
    }

    /// <summary>
    /// This method is an alternative to WPF's
    /// <see cref="VisualTreeHelper.GetParent"/> method, which also
    /// supports content elements. Keep in mind that for content element,
    /// this method falls back to the logical tree of the element!
    /// </summary>
    /// <param name="child">The item to be processed.</param>
    /// <returns>The submitted item's parent, if available. Otherwise
    /// null.</returns>
    public static DependencyObject GetParentObject(this DependencyObject child)
    {
        if (child == null) return null;

        // handle content elements separately
        if (child is ContentElement contentElement)
        {
            DependencyObject parent = ContentOperations.GetParent(contentElement);
            if (parent != null) return parent;

            return contentElement is FrameworkContentElement fce ? fce.Parent : null;
        }

        var childParent = VisualTreeHelper.GetParent(child);
        if (childParent != null)
        {
            return childParent;
        }

        // also try searching for parent in framework elements (such as DockPanel, etc)
        if (child is FrameworkElement frameworkElement)
        {
            DependencyObject parent = frameworkElement.Parent;
            if (parent != null) return parent;
        }

        return null;
    }
}
